# from fastapi.exceptions import HTTPException
import datetime

from starlette.exceptions import HTTPException  # 官方推荐注册异常处理器时，应该注册到来自 Starlette 的 HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel, ValidationError, errors
from fastapi.encoders import jsonable_encoder
from utils.log_util import logger as log
from minio.error import MinioException
from sqlalchemy.exc import SQLAlchemyError
from orjson import JSONDecodeError


# 全局异常
async def global_exception_handler(request, exc):
    if exc.status_code == 500:
        err_msg = 'Server Internal Error'
    else:
        err_msg = exc.detail

    log.error(err_msg)

    return JSONResponse(
        status_code=exc.status_code,
        content={
            "msg": err_msg,
            "success": False,
            "code": exc.status_code,
            "timestamp": datetime.datetime.now().timestamp()
        })


async def minio_exception_handler(request, exc):
    log.error(exc)
    return JSONResponse({
        "msg": exc.message,
        "success": False,
        "code": 500,
        "timestamp": datetime.datetime.now().timestamp()
    })


async def pydantic_validation_exception_handler(request, exc):
    """
    处理 Pydantic 验证错误。
    """
    log.error(exc.errors())
    print("got it !")
    err_fields = {}
    for error in exc.errors():
        item = error["loc"][1] if isinstance(error["loc"], tuple) else error["loc"]
        msg = error["msg"]
        err_type = error["type"]

        if err_type not in err_fields:
            err_fields[err_type] = []
            err_fields[err_type].append({"item": item, "msg": msg})
        else:
            err_fields[err_type].append({"item": item, "msg": msg})
        # if isinstance(error["type"], errors.TypeError):
        #     fields[error["loc"][0]] = "必须是" + error["expected_type"]
        # elif isinstance(error["type"], errors.ValueError):
        #     fields[error["loc"][0]] = "不符合规定的值"
        # else:
        #     fields[error["loc"][0]] = "无效输入"
    # print(exc.errors, str(exc))
    return JSONResponse({
        "msg": "Pydantic字段验证错误！",
        "success": False,
        "code": 422,
        "data": err_fields,
        "timestamp": datetime.datetime.now().timestamp()
    })


async def database_error_handler(request, exc: SQLAlchemyError):
    log.info(exc.__dict__)
    return JSONResponse({
        "msg": "Sqlalchemy数据库sql语法错误！",
        "success": False,
        "code": 500,
        "data": str(exc),
        "timestamp": datetime.datetime.now().timestamp()
    })


# 定义全局exception对应用的handler
global_exception_handlers = {
    HTTPException: global_exception_handler,
    MinioException: minio_exception_handler,
    RequestValidationError: pydantic_validation_exception_handler,
    ValidationError: pydantic_validation_exception_handler,
    SQLAlchemyError: database_error_handler,
    JSONDecodeError: global_exception_handler
}


# 自定义exception的基类
class BaseAPIException(HTTPException):
    status_code = 400
    detail = 'api error'

    def __init__(self, detail: str = None, status_code: int = None):
        self.detail = detail or self.detail
        self.status_code = status_code or self.status_code
